package com.livestocksolutions.ui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AbstractDocument;

import com.livestocksolutions.LivestockSolutions;
import com.livestocksolutions.UsableItem;
import com.livestocksolutions.UsedItem;
import com.livestocksolutions.util.Comparators;
import com.livestocksolutions.util.DecimalDocumentFilter;
import com.livestocksolutions.util.Table;
import com.livestocksolutions.util.UsableItemList;

/**
 * Display details relating to any Item, or a particular <tt>T</tt>.
 * @author Ken DeVries
 * @author Adam Parr
 * 
 * @.modified 19 March 2013
 *
 * @param <T> A subclass of UsableItem.
 * @param <A> A subclass of UsedItem which is related to <tt>T</tt>.
 */
public abstract class ItemPanel<T extends UsableItem<A>,A extends UsedItem> extends JPanel implements TabbedInterface {
	private static final long serialVersionUID = 1L;
	/**
	 * String that will be placed into all Strings 
	 */
	private final String typeString;
	
	/**
	 * A check to determine if the item in its current state is valid to be saved.
	 */
	protected DocumentListener dl;
	
	/**
	 * Constructor to create a TabbedInterface of a sub class of a UsableItem.
	 * @param type String containing the type of <tt>T</tt> that will be shown in the GUI.
	 */
	protected ItemPanel(String type){
		this.typeString=type;
		
		JScrollPane jsp = new JScrollPane();
		setLayout(new BorderLayout(0, 0));
		jsp.setViewportView(panel);
		jsp.setViewportBorder(BorderFactory.createEmptyBorder());

		add(jsp);
		panel.setLayout(new BorderLayout(10, 10));

		AdjustmentListener al = new AdjustmentListener(){
			@Override
			public void adjustmentValueChanged(AdjustmentEvent evt) {
				panel.repaint();
			}
		};
		jsp.getHorizontalScrollBar().addAdjustmentListener(al);
		jsp.getVerticalScrollBar().addAdjustmentListener(al);

		txtName.setColumns(20);
		((AbstractDocument)spinnerQuantity.getDocument()).setDocumentFilter(new DecimalDocumentFilter(0d,Double.POSITIVE_INFINITY));
		cbMeasurement.setModel(new DefaultComboBoxModel(new String[] {"ml", "l", "mg", "g", "kg", "Tablet"}));
	}
	
	/**
	 * The initial view for this tab.
	 * Shows all <tt>T</tt>s that are in the system.
	 */
	public static final int ITEM_LIST = 0;
	/**
	 * To create a new <tt>T</tt>.
	 */
	public static final int VIEW_NEW_ITEM=1;
	/**
	 * To view a <tt>T</tt> details.
	 */
	public static final int VIEW=2;
	
	/**
	 * Sort the UsableItem list by name.
	 */
	protected static final int LIST_ORDER_NAME = 0;
	/**
	 * Sort the UsableItem list by using quantity given.
	 */
	protected static final int LIST_ORDER_QTY	= 1;
	
	/**
	 * Order the UsableItem list.
	 * @see #LIST_ORDER_NAME
	 * @see #LIST_ORDER_QTY
	 */
	protected int orderItemItemListBy = LIST_ORDER_NAME;
	/**
	 * The sort direction. Ascending : 1, Descending -1;
	 */
	protected int orderItemItemHighToLow = 1;
	
	private JTextField txtName = new JTextField("-1");
	private JTextArea txtDescription = new JTextArea();
	private JTextField spinnerQuantity = new JTextField();
	private JComboBox cbMeasurement = new JComboBox();
	private Table mixture;

	private ArrayList<UsableItemList<T>> iList = new ArrayList<UsableItemList<T>>();
	
	/**
	 * Determine if the editable details of a <tt>T</tt> is editable.
	 */
	protected boolean edit = false;
	
	/**
	 * The current view.
	 * 
	 * @see #ITEM_LIST
	 * @see #VIEW_NEW_ITEM
	 * @see #VIEW
	 */
	private int viewing = -1;
	
	/**
	 * The ID of the <tt>T</tt> we are Viewing.
	 */
	protected long itemViewID = 0;
	
	protected final JPanel panel = new JPanel();

	
	@Override
	public void displayPanel() {
		int panel = viewing;
		if(viewing==ITEM_LIST) {
			viewing=-1;
			panel = ITEM_LIST;
		}
		displayPanel(panel);
	}

	/**
	 * @see #ITEM_LIST
	 * @see #VIEW_NEW_ITEM
	 * @see #VIEW
	 */
	@Override
	public void displayPanel(int panel) {
		switch (panel){
		case ITEM_LIST:
			if(viewing!=ITEM_LIST){
				createHomePanel();
			}
			break;
		case VIEW_NEW_ITEM:
			if(viewing!=VIEW_NEW_ITEM){
				createItemPanel(-1);
			}
			break;
		case VIEW:
			createItemPanel(itemViewID);
			break;
		default:
			createHomePanel();
		}
	}
	
	/**
	 * Create a list of <tt>T</tt> Item Usage that are in the system.
	 */
	private void createHomePanel(){
		viewing=ITEM_LIST;
		
		itemViewID = 0;
		panel.setLayout(new BorderLayout());
		final int ITEM	 	= 0;
		final int DESCRIPTION= 1;
		final int QTY 		= 2;
		
		final Table itemPanel = new Table("Items",false,
			typeString+" Name","Description","Measurement");
		itemPanel.setEmptyMessage("There are no "+typeString+"s to show.");
		itemPanel.setHeaderClickable(DESCRIPTION, false);
		
		new Thread(){
			@Override
			public void run(){
				while(!LivestockSolutions.isReady()){
					try {
						sleep(500);
					} catch (InterruptedException e) {}
					if(LivestockSolutions.close){
						return;
					}
				}
				
				itemPanel.setHeaderOrderedBy(orderItemItemListBy==LIST_ORDER_NAME?ITEM:orderItemItemListBy==LIST_ORDER_QTY?QTY:ITEM, orderItemItemHighToLow==1);
				itemPanel.addHeaderMouseListener(ITEM, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderItemItemHighToLow = orderItemItemHighToLow*(orderItemItemListBy==LIST_ORDER_NAME?-1:1);
						orderItemItemListBy = LIST_ORDER_NAME;
						createHomePanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				itemPanel.addHeaderMouseListener(QTY, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderItemItemHighToLow = orderItemItemHighToLow*(orderItemItemListBy==LIST_ORDER_QTY?-1:1);
						orderItemItemListBy = LIST_ORDER_QTY;
						createHomePanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				T[] cList = getList();
				Arrays.sort(cList, 
					orderItemItemListBy==LIST_ORDER_NAME?
							orderItemItemHighToLow==1?Comparators.usableItemComparatorName:Collections.reverseOrder(Comparators.usableItemComparatorName)
					:orderItemItemHighToLow==1?Comparators.usableItemComparatorQty:Collections.reverseOrder(Comparators.usableItemComparatorQty));

				for(int x=0; x<cList.length; x++){
					int mixLen = cList[x].getIncludedMixtures().length;
					itemPanel.addRow(
						new JLabel(cList[x].getName()),
						new JLabel(cList[x].getDescription()),
						new JLabel((mixLen>0?"Mixture of "+mixLen+": creates "+cList[x].getQuantity()+" ":" ")+cList[x].getMeasurement()));
					
					final long id = cList[x].getID();
					itemPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							if(createItemPanel(id)){
								// Show Item not found message?
							}
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				validate();
			}
		}.start();

		panel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		
		JButton btnNewCattle = new JButton("New "+typeString);
		btnNewCattle.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				createItemPanel(-1L);
			}
		});
		buttonPanel.add(btnNewCattle);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(itemPanel,BorderLayout.CENTER);
		panel.add(container,BorderLayout.NORTH);
		panel.repaint();
	}
	
	/**
	 * Show the details for this Item with the given ID
	 * @param itemID The internal Id that identifies this Item
	 * @return <tt>true</tt> If a Item with the Id exists and was shown, <tt>false</tt> otherwise.
	 */
	public boolean createItemPanel(final long itemID){
		viewing=VIEW;
		
		/**
		 * Add or Remove button Column in Table.
		 */
		final int OPTION = 0;
		/**
		 * Name Column in Table
		 */
		final int NAME = 1;
		/**
		 * Mixture amount used Column in Table
		 */
		final int AMOUNT = 2;
		
		boolean refresh=true;
		if(itemViewID != itemID){
			itemViewID = itemID;
			edit=false;
			txtName.setText("-1");
		}
		
		edit=itemID==-1?true:edit;
		if(txtName.getText().equals("-1")){
			refresh = false;
		}
		panel.setLayout(new BorderLayout(10, 10));
		panel.removeAll();
		 
		T item = (T)LivestockSolutions.getUsableItemByID(itemID);

		if(item!=null || itemID==-1){
			JPanel topPanel = new JPanel();
			topPanel.setBorder(new EmptyBorder(0, 0, 5, 0));
			
			JPanel flowPanel = new JPanel();
			flowPanel.add(topPanel);
			
			JPanel container = new JPanel();
			container.setLayout(new BorderLayout(10, 10));
			container.add(flowPanel,BorderLayout.CENTER);
			panel.add(container,BorderLayout.NORTH);
			
			topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS));
			
			// Labels
			JPanel valueNamePanel = new JPanel();
			topPanel.add(valueNamePanel);
			valueNamePanel.setBorder(new EmptyBorder(5, 0, 0, 0));
			valueNamePanel.setLayout(new BoxLayout(valueNamePanel, BoxLayout.PAGE_AXIS));
			
			JPanel lblNamePanel = new JPanel();
			lblNamePanel.setBorder(new EmptyBorder(0, 0, 5, 0));
			valueNamePanel.add(lblNamePanel);
			lblNamePanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
			lblNamePanel.add(new JLabel("Name:"));
						
			JPanel lblQuantityPanel = new JPanel();
			lblQuantityPanel.setBorder(new EmptyBorder(10, 0, 5, 0));
			lblQuantityPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
			valueNamePanel.add(lblQuantityPanel);
			final JLabel measuermentLabel = new JLabel("Measurement Units:");
			lblQuantityPanel.add(measuermentLabel);
			
			// Values
			JPanel valuePanel = new JPanel();
			topPanel.add(valuePanel);
			valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.PAGE_AXIS));
			
			JPanel nameValuePanel = new JPanel();
			nameValuePanel.setBorder(new EmptyBorder(0, 0, 5, 0));
			valuePanel.add(nameValuePanel);
			nameValuePanel.setLayout(new BorderLayout(0, 0));
			nameValuePanel.add(txtName);
			
			JPanel quantityValuePanel = new JPanel();
			valuePanel.add(quantityValuePanel);
			quantityValuePanel.setBorder(new EmptyBorder(0, 0, 0, 10));
			quantityValuePanel.setLayout(new BoxLayout(quantityValuePanel, BoxLayout.X_AXIS));
			
			JPanel spinnerQtyPanel = new JPanel();
			spinnerQtyPanel.setBorder(new EmptyBorder(0, 0, 0, 5));
			quantityValuePanel.add(spinnerQtyPanel);
			spinnerQtyPanel.setLayout(new BoxLayout(spinnerQtyPanel, BoxLayout.X_AXIS));
			
			spinnerQtyPanel.add(spinnerQuantity);
			
			JPanel cbMeasurementPanel = new JPanel();
			quantityValuePanel.add(cbMeasurementPanel);
			cbMeasurementPanel.setLayout(new BoxLayout(cbMeasurementPanel, BoxLayout.X_AXIS));
			
			cbMeasurementPanel.add(cbMeasurement);
			cbMeasurement.setEnabled(edit);
			
			JPanel listPanel = new JPanel();
			panel.add(listPanel, BorderLayout.CENTER);
			listPanel.setLayout(new BorderLayout(0, 0));
			
			JPanel descriptionPanel = new JPanel();
			descriptionPanel.setBorder(new EmptyBorder(0, 5, 5, 5));
			listPanel.add(descriptionPanel, BorderLayout.NORTH);
			descriptionPanel.setLayout(new BorderLayout(0, 5));
			
			descriptionPanel.add(new JLabel("Description:"), BorderLayout.NORTH);
			txtDescription.setRows(3);
			descriptionPanel.add(txtDescription, BorderLayout.CENTER);
			
			final boolean callSave = add(item,valueNamePanel,valuePanel,descriptionPanel);
			
			if(item!=null && item.getIncludedMixtures().length>0){
				// Is a mixture
				measuermentLabel.setText("Mixture Creates:");
				spinnerQuantity.setVisible(true);
			}else{
				measuermentLabel.setText("Measurement Units:");
				spinnerQuantity.setVisible(false);
			}
			
			final JButton btnCreateSave = new JButton(itemViewID==-1?"Create":edit?"Save":"Edit");
			
			/**
			 * A check to determine if the item in its current state is valid to be saved.
			 * @see #doCheck()
			 */
			final DocumentListener dl = new DocumentListener() {
				public void changedUpdate(DocumentEvent e) {
					doCheck();
				}
				public void removeUpdate(DocumentEvent e) {
					doCheck();
				}
				public void insertUpdate(DocumentEvent e) {
					doCheck();
				}
				
				/**
				 * Checks to see if it is OK to save the item as it currently is.<br>
				 * Disables the save button if it is not OK, enables it if it is.
				 */
				private void doCheck(){
					boolean valid=false;
					if(!txtName.getText().trim().equals("")&&edit){
						valid=true;
						if(mixture.getNumRows()>1){
							// spinnerQuantity must be set
							if(!spinnerQuantity.getText().trim().equals("")){
								// Check that each ratio is not empty
								for(int x=0; x<mixture.getNumRows()-1; x++){
									Component[] c=mixture.getRowData(x);
									if(((JTextField)((JPanel)c[AMOUNT]).getComponent(0)).getText().trim().equals("")){
										valid=false;
										break;
									}
								}
							}else{
								valid=false;
							}
						}
					}
					valid=ItemPanel.this.doCheck(valid);
					btnCreateSave.setEnabled(edit?valid:true);
				}
			};
			
			if(!refresh){
				mixture = new Table("Mixture",true,"",typeString+" Name","Amount");
				mixture.setHeaderClickable(OPTION, false);
				mixture.setHeaderClickable(NAME, false);
				mixture.setHeaderClickable(AMOUNT, false);
				mixture.setEmptyMessage(new JLabel(edit?"At least one other "+typeString+" item needs to be created before a mixture can be created":"Not a mixture"));
	
				txtName.getDocument().addDocumentListener(dl);
				spinnerQuantity.getDocument().addDocumentListener(dl);
				
				if(item!=null){
					txtName.setText(item.getName());
					spinnerQuantity.setText(String.valueOf(item.getQuantity()));
					txtDescription.setText(item.getDescription());
					cbMeasurement.setSelectedItem(item.getMeasurement());
				}else{
					txtName.setText("");
					spinnerQuantity.setText("");
					txtDescription.setText("");
					cbMeasurement.setSelectedIndex(0);
				}
					
				iList.clear();
				ArrayList<T> fArrayList = new ArrayList<T>(Arrays.asList(getList()));
				Iterator<T> i = fArrayList.iterator();
				HashMap<T,Boolean> itemCont=new HashMap<T,Boolean>();
				while(i.hasNext()){
					T f = i.next();
					if(f!=item && !contains(itemCont,f,item)){
						iList.add(new UsableItemList<T>(f));
					}
				}
				
				if(iList.size()>0){
					JButton addMixture = new JButton("+ Add");
					JPanel jp = new JPanel();
					jp.add(addMixture);
					mixture.addRow(jp);
					mixture.setRowClickable(false);
					addMixture.addActionListener(new ActionListener(){
						@Override
						public void actionPerformed(ActionEvent arg0) {
							measuermentLabel.setText("Mixture Creates:");
							spinnerQuantity.setVisible(true);
							JButton removeMixture = new JButton("- Remove");
							int index = mixture.getNumRows()-1;
							JComboBox itemName = new JComboBox(iList.toArray());
							JTextField itemAmount = new JTextField();
							itemAmount.setColumns(7);
							itemAmount.setEditable(edit);
							JComboBox itemMixture = new JComboBox();
							JPanel mixtureAmount = new JPanel();
							mixtureAmount.add(itemAmount);
							mixtureAmount.add(itemMixture);
							itemAmount.getDocument().addDocumentListener(dl);
							((AbstractDocument)itemAmount.getDocument()).setDocumentFilter(new DecimalDocumentFilter(0d,Double.POSITIVE_INFINITY));
							
							JPanel jp = new JPanel();
							jp.add(removeMixture);
							mixture.addRow(index,jp,itemName,mixtureAmount);
							mixture.setRowClickable(index,false);
							dl.changedUpdate(null);
							final String id = mixture.getRowID(index);
							removeMixture.addActionListener(new ActionListener(){
								@Override
								public void actionPerformed(ActionEvent arg0) {
									mixture.remove(id);
									dl.changedUpdate(null);
									if(mixture.getNumRows()<=1){
										measuermentLabel.setText("Measurement Units:");
										spinnerQuantity.setVisible(false);
									}
								}
							});
							
							itemName.addActionListener(new ActionListener () {
							    public void actionPerformed(ActionEvent e) {
							        Component[] c=mixture.getRowData(id);
							        String type=((UsableItemList<T>)((JComboBox)c[NAME]).getSelectedItem()).getItem().getMeasurement();
							        
							        String[] measurementSelect = new String[] {"ml", "l", "mg", "g", "kg", "Tablet"};
									if(type.toLowerCase().equals("ml")||type.toLowerCase().equals("l")){
										measurementSelect = new String[] {"ml", "l"};
									}else if(type.toLowerCase().equals("mg")||type.toLowerCase().equals("g")||type.toLowerCase().equals("kg")){
										measurementSelect = new String[] {"mg","g", "kg"};
									}else if(type.toLowerCase().equals("tablet")){
										measurementSelect = new String[] {"Tablet"};
									}
									JComboBox measurementUnit=((JComboBox)((JPanel)c[AMOUNT]).getComponent(1));
									Object selected = measurementUnit.getSelectedItem();
									measurementUnit.setModel(new DefaultComboBoxModel(measurementSelect));
									if(selected!=null){
										measurementUnit.setSelectedItem(selected);
									}else{
										measurementUnit.setSelectedItem(type);
									}
									if(measurementUnit.getSelectedItem()==null){
										measurementUnit.setSelectedItem(type);
									}
							    }
							});
							// Select the currently item in the list to call the above ActionListener
							itemName.setSelectedItem(itemName.getSelectedItem());
							if(itemMixture.getSelectedIndex()==-1){
								itemMixture.setSelectedItem(((UsableItemList<T>)itemName.getSelectedItem()).getItem().getMeasurement());
							}
							mixture.validate();
						}
					});
					
					if(item!=null){
						for(UsedItem uf:item.getIncludedMixtures()){	
							// Add new row and populate with data.
							addMixture.doClick();
							Component[] c = mixture.getRowData(mixture.getNumRows()-2);
							if(uf!=null){
								if(edit){
									((JComboBox)c[NAME]).setSelectedItem(new UsableItemList<T>((T)uf.getItem()));
									((JTextField)((JPanel)c[AMOUNT]).getComponent(0)).setText(String.valueOf(uf.getUnits()));
									((JComboBox)((JPanel)c[AMOUNT]).getComponent(1)).setSelectedItem(uf.getMeasurement());
								}else{
									JPanel j = (JPanel)c[NAME].getParent();
									j.removeAll();
									j.add(new JLabel(uf.getItem().getName()));
									
									j = (JPanel)c[AMOUNT].getParent();
									j.removeAll();
									j.add(new JLabel(uf.getUnits()+" "+uf.getMeasurement()));
								}
							}
						}
					}
					
					if(!edit){
						mixture.setColumnVisible(OPTION, false);
						mixture.remove(mixture.getNumRows()-1);
					}
				}
			}	
			listPanel.add(mixture, BorderLayout.CENTER);
			
			txtName.setEditable(edit);
			txtDescription.setEditable(edit);
			spinnerQuantity.setEditable(edit);
			cbMeasurement.setEditable(edit);
			
			/**
			 * The Item that is being shown.
			 */
			final long itemViewID = this.itemViewID;
			JButton btnHome = new JButton(typeString+" List");
			btnHome.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					edit=false;
					txtName.setText("-1");
					viewing=-1;
	
					displayPanel(ITEM_LIST);
				}
			});
			
			JPanel buttonMenuLeft = new JPanel();
			JPanel buttonMenuRight = new JPanel();
			((FlowLayout)buttonMenuLeft.getLayout()).setAlignment(FlowLayout.LEFT);
			((FlowLayout)buttonMenuRight.getLayout()).setAlignment(FlowLayout.RIGHT);
			buttonMenuLeft.add(btnHome);
			
			if(itemViewID==-1 || LivestockSolutions.getUsableItemByID(itemViewID)!=null){
				JButton btnCancel = new JButton(itemViewID!=-1?"Cancel":"Clear");
				btnCancel.setVisible(edit);
				btnCancel.addActionListener(new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						edit=false;
						txtName.setText("-1");
						displayPanel(viewing);
					}
				});
				
				btnCreateSave.addActionListener(new ActionListener() {
					@SuppressWarnings("unchecked")
					@Override
					public void actionPerformed(ActionEvent ev) {
						if(edit){
							T i = (T)LivestockSolutions.getUsableItemByID(itemViewID);
							if(i==null){
								i = newItem();
							}

							i.setName(txtName.getText());
							i.setDescription(txtDescription.getText());
							i.setMeasurement((String)cbMeasurement.getSelectedItem());
							
							// Create items to add first, that way if an Exception were to occur due to some invalid data old data will not be lost.
							A[] usedItem=(A[])new UsedItem[mixture.getNumRows()>1?mixture.getNumRows()-1:0];
							for(int x=0; x<mixture.getNumRows()-1; x++){
								Component[] c = mixture.getRowData(x);
								usedItem[x]=(A)new UsedItem(((UsableItemList<T>)((JComboBox)c[NAME]).getSelectedItem()).getItem(),Double.parseDouble(((JTextField)((JPanel)c[AMOUNT]).getComponent(0)).getText()),(String)((JComboBox)((JPanel)c[AMOUNT]).getComponent(1)).getSelectedItem());
							}
							
							// Remove all mixtures to avoid duplicating.
							for(A uf:i.getIncludedMixtures()){
								i.removeIncludedMixture(uf);
							}
							
							// Add in all new mixture elements.
							if(mixture.getNumRows()>1){
								i.setQuantity(Double.parseDouble(spinnerQuantity.getText()));
								for(A uf:usedItem){
									if(uf!=null){
										i.addIncludedMixture(uf);
									}
								}
							}

							if(((callSave&&save(i))||!callSave)&&LivestockSolutions.addUsableItem(i)){
								ItemPanel.this.itemViewID=i.getID();
								txtName.setText("-1");
								edit=!edit;
							}else{
								JOptionPane.showMessageDialog(MainFrame.getInstance(),"Failed to save changes.","Failed to Save", JOptionPane.OK_OPTION);
							}
						}else{
							txtName.setText("-1");
							edit=!edit;
						}
						displayPanel(viewing);
					}
				});
				
				buttonMenuRight.add(btnCreateSave);
				buttonMenuRight.add(btnCancel);
				
				JPanel buttonMenu = new JPanel();
				buttonMenu.setLayout(new BorderLayout());
				buttonMenu.add(buttonMenuLeft,BorderLayout.WEST);
				buttonMenu.add(buttonMenuRight,BorderLayout.EAST);
				container.add(buttonMenu,BorderLayout.NORTH);
			}
		}else{
			panel.removeAll();
			panel.setLayout(new BorderLayout(10, 10));

			JPanel flow =new JPanel();
			JLabel label = new JLabel("No Such Item can be found with the given internal id: "+itemID+".");
			flow.add(label);
			panel.add(flow, BorderLayout.CENTER);
			panel.repaint();
			return false;
		}
		panel.repaint();
		return true;
	}
	
	/**
	 * A recursive method that will check if the <tt>T</tt> item contains the <tt>T</tt> contains as part of a mixture.
	 * @param useMap A Hashmap where previously checked <tt>T</tt> sand their results can be stored to reduce
	 *               the amount of duplicate work.
	 * @param item The <tt>T</tt> to check.
	 * @param contains The <tt>T</tt> to check if item contains it.
	 * @return <tt>true</tt> if contains is used within item at any point, <tt>false</tt> otherwise.
	 */
	protected boolean contains(HashMap<T,Boolean> useMap, T item, T contains){
		boolean c=false;
		Boolean b=useMap.get(item);
		if(b!=null){
			return b;
		}
		
		for(A uf:item.getIncludedMixtures()){
			if(uf.getItem()==contains){
				useMap.put(item,true);
				return true;
			}
			c=contains(useMap,(T)uf.getItem(),contains);
			if(c){
				break;
			}
		}
		useMap.put(item,c);
		return c;
	}
	
	/**
	 * Additional attributes that may need to be modified when saving.<br>
	 * Only called when {@link #add(T, JPanel, JPanel, JPanel)} returns <tt>true</tt>.<br>
	 * <br>
	 * Sub classes that extend ItemPanel can override this method to save additional data that it may introduce.
	 * @param item The Item being saved.
	 * @return <tt>true</tt> if everything was added correctly, <tt>false</tt> otherwise.
	 */
	protected boolean save(T item){
		return true;
	}
	
	/**
	 * Add additional Components to the interface to allow more details.<br>
	 * <br>
	 * Sub classes that extend ItemPanel can override this method to save additional data that it may introduce.
	 * @param item The item that is being shown.
	 * @param nameColumn JPanel that contains all JLabels of the list items.
	 * @param valueColumn JPanel that contains Components data.
	 * @param aditional JPanel that follows after, but before the table at the end.
	 * @return <tt>true</tt> to indicate there are additional attributes that will be modified during the saving process,
	 *         <tt>false</tt> When there is no need to call {@link #save(T)}.
	 */
	protected boolean add(T item, JPanel nameColumn, JPanel valueColumn, JPanel aditional){
		return false;
	}
	
	/**
	 * Allows additional validation of the data/additional data that may have been added through {@link #add(T, JPanel, JPanel, JPanel)}.<br>
	 * <br>
	 * Sub classes that extend ItemPanel can override this method to save additional data that it may introduce.
	 * @param isValid Current value of the validation on the Components provided. 
	 *        <tt>true</tt> indicates that the data is valid and saving will be allowed, <tt>false</tt> indicates that at least one
	 *        attribute is invalid and saving will not be allowed (overwritten by returning a value other than <tt>false</tt>). 
	 * @return <tt>true</tt> if data is validated and valid (allow saving), <tt>false</tt> otherwise (do not allow saving).
	 */
	protected abstract boolean doCheck(boolean isValid);

	/**
	 * Get a list of items that are of type <tt>T</tt> that can be used.<br>
	 * Sub classes that extend ItemPanel can override this method to provide an accurate list of <tt>T</tt> items that can be used.
	 * @return A list of Items that can be used in this Item.
	 */
	protected abstract T[] getList();
	
	/**
	 * Get a new Item of type <tt>T</tt>.<br>
	 * Sub classes that extend ItemPanel can override this method to provide a correct type Object.
	 * @return A new Object of the provided type <tt>T</tt>.
	 */
	protected abstract T newItem();

	@Override
	public long getID() {
		return itemViewID;
	}
}
